/*
 *   Copyright (C) 2009  Jens Kieselbach
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You may obtain a copy of the License at http://www.gnu.org/licenses/gpl.html
 */

package de.kieselbach.swing

import de.kieselbach.swing.border.*
import groovy.swing.SwingBuilder
import javax.swing.*

import java.awt.BorderLayout
import java.awt.Color
import java.awt.Font
import java.awt.GridBagConstraints

class ButtonedPane extends JPanel {

    final static def COLLAPSE_ICON = new ImageIcon(ButtonedPane.class.getResource('/de/kieselbach/swing/image/collapse.png'))
    final static def EXPAND_ICON = new ImageIcon(ButtonedPane.class.getResource('/de/kieselbach/swing/image/expand.png'))

    final def borderColor
	final def activeBorder
	final def inactiveBorder
	
    def contentPanel
    def gridBagLayout

    def currentAnimate
    def sizes = [:]
    def count = 0
    def minDelay = 40

    ButtonedPane() {

        super(new BorderLayout(0, 0))

        borderColor = UIUtilities.lineBorderColor
		activeBorder = CustomLineBorder.create(borderColor, '478962', 3)
		inactiveBorder = CustomLineBorder.create(borderColor, '47896321', 3)
		
        def sb = new SwingBuilder()
        add(sb.scrollPane(border: null, viewportBorder: BorderFactory.createEmptyBorder(0, 0, 0, 3), horizontalScrollBarPolicy: ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER) {

            contentPanel = sb.panel() {
                gridBagLayout = sb.gridBagLayout()
                sb.panel(minimumSize: [0, 0], preferredSize: [0, 0], constraints: gbc(gridx: 0, gridy: 1000, gridwidth: 1, gridheight: 1, weightx: 1.0, weighty: 1.0, fill: GridBagConstraints.BOTH, insets: [0, 0, 0, 0]))
            }
        }, BorderLayout.CENTER)
    }

    def addPanel(def panel, def title, def expanded) {

        def sb = new SwingBuilder()
        sb.panel(contentPanel) {
            buttonbox = sb.panel(constraints: gbc(gridx: 0, gridy: count, gridwidth: 1, gridheight: 1, weightx: 1.0, weighty: 0.0, fill: GridBagConstraints.HORIZONTAL, insets: [count > 0 ? 10 : 0, 0, 0, 0])) {
                sb.borderLayout()

                def button = sb.button(title, icon: expanded ? COLLAPSE_ICON : EXPAND_ICON, /*ui: new RightIconButtonUI(),*/ requestFocusEnabled: false,
                    focusPainted: false, horizontalTextPosition: SwingConstants.LEFT, horizontalAlignment: SwingConstants.LEFT,
                    font: font.deriveFont(Font.BOLD), constraints: BorderLayout.NORTH)

                def box = sb.panel(border: BorderFactory.createCompoundBorder(CustomLineBorder.create(borderColor, '41236'), BorderFactory.createEmptyBorder(5, 5, 5, 5)),
                    visible: expanded, constraints: BorderLayout.CENTER) {
                    sb.borderLayout()

                    sb.panel(constraints: BorderLayout.CENTER) {
                        sb.boxLayout(axis: BoxLayout.Y_AXIS)

                        widget(panel)
                    }
                }

				button.border = expanded ? activeBorder : inactiveBorder
                button.actionPerformed = {event ->
                    if (box.visible) {
                        collapse(button, box)
                    }
                    else {
                        expand(button, box)
                    }
                }
            }
        }

        count++
    }

    void expand(def button, def box) {

        if (currentAnimate == null) {
            currentAnimate = {

                int height = sizes[box]
                if (height == null || height <= 0) {
                    height = box.preferredSize.@height
                }

                if (height > 0) {

                    def first = true
                    def time = 0L

                    try {
                        [0.25, 0.5, 0.7, 0.8, 0.9, 0.95, 0.97, 0.99, 0.995].each() {phase ->

                            def dur = System.currentTimeMillis() - time;
                            if (dur < minDelay) {

                                Thread.sleep(minDelay - dur)
                            }
                            time = System.currentTimeMillis()

                            SwingUtilities.invokeAndWait {

                                box.preferredSize = [button.width, (height * phase) as Integer]

                                if (first) {
                                    button.icon = COLLAPSE_ICON
									button.border = activeBorder
                                    box.visible = true;
                                    first = false
                                }

                                box.invalidate()
                                validateTree()
                                repaint()
                            }
                        }
                    }
                    catch (InterruptedException ie) {
                    }
                }

                SwingUtilities.invokeAndWait {

                    box.preferredSize = null

                    box.visible = true;
                    box.invalidate()
                    validateTree()
                    repaint()
                }

                currentAnimate = null;
            }

            new Thread(currentAnimate).start()
        }
    }

    void collapse(def button, def box) {

        if (currentAnimate == null) {
            currentAnimate = {

                int height = box.height
                sizes[box] = height
                def time = 0L

                try {
                    [0.75, 0.5, 0.3, 0.2, 0.1, 0.05, 0.03, 0.01, 0.005].each() {phase ->

                        def dur = System.currentTimeMillis() - time;
                        if (dur < minDelay) {

                            Thread.sleep(minDelay - dur)
                        }
                        time = System.currentTimeMillis()

                        SwingUtilities.invokeAndWait {

                            box.preferredSize = [button.width, (height * phase) as Integer]

                            box.invalidate()
                            validateTree()
                            repaint()
                        }
                    }
                }
                catch (InterruptedException ie) {
                }

                SwingUtilities.invokeAndWait {

                    box.visible = false;
                    button.icon = EXPAND_ICON
					button.border = inactiveBorder
					
                    box.invalidate()
                    validateTree()
                    repaint()
                }

                currentAnimate = null;
            }

            new Thread(currentAnimate).start()
        }
    }
}